Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Text
Imports System.Windows.Forms

Imports WinXound_Net.gVar



Public Class wxCompilerConsole

    Public Event CompilerCompleted(ByVal mErrorLine As String, ByVal mWaveFile As String)
    Public Event ButtonFindErrorClick()

    Private wxOutputBuffer As Byte() = New Byte(1023) {}
    Private wxErrorBuffer As Byte() = New Byte(1023) {}

    ''Delegate for SCI_EDIT AppendText
    Private Delegate Sub AppendTextDelegate(ByVal mOutputWin As SCI_EDIT, _
                                            ByVal mString As String)
    Dim d As New AppendTextDelegate(AddressOf AppendText)



    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        ConfigureSciEditOW(SCI_Output)
        ConfigureSciEditOW(SCI_Error)

    End Sub

    Public Property Filename() As String
        Get
            Return process1.StartInfo.FileName
        End Get
        Set(ByVal value As String)
            process1.StartInfo.FileName = value
        End Set
    End Property

    Public Property Arguments() As String
        Get
            Return process1.StartInfo.Arguments
        End Get
        Set(ByVal value As String)
            process1.StartInfo.Arguments = value
        End Set
    End Property

    Public ReadOnly Property ProcessActive() As Boolean
        Get
            Try
                Return Not process1.HasExited
            Catch ex As Exception
            End Try
        End Get
    End Property

    Public ReadOnly Property OutputText() As String
        Get
            Dim mString As String = "Compiler Output:" & vbCrLf & vbCrLf & _
                                    SCI_Output.GetText & vbCrLf & vbCrLf & _
                                    "=============================================" & vbCrLf & vbCrLf & _
                                    "Compiler Info:" & vbCrLf & vbCrLf & _
                                    SCI_Error.GetText
            Return mString
        End Get
    End Property

    Public Sub ClearText()
        Try
            SCI_Output.SetReadOnly(False)
            SCI_Output.ClearAll()
            SCI_Output.SetReadOnly(True)
            SCI_Error.SetReadOnly(False)
            SCI_Error.ClearAll()
            SCI_Error.SetReadOnly(True)
        Catch ex As Exception
        End Try
    End Sub

    Public Sub StopCompiler()
        Try
            If Not process1.HasExited Then
                process1.Kill()
            End If
        Catch ex As Exception
            ''wxMessageError(ex.Message, "wxCompilerConsole - StopCompiler Error")
        End Try
    End Sub

    Public Function StartCompiler(Optional ByVal mVerbose As Boolean = False) As Boolean

        Try
            'Check for other compiler running process
            If Not process1.HasExited Then
                MessageBox.Show("CSound Compiler already running!" & vbCrLf & _
                                "Stop it manually and retry", _
                                "WinXound Info - Compiler busy", _
                                MessageBoxButtons.OK, _
                                MessageBoxIcon.Information)
                Exit Function
            End If
        Catch ex As Exception
        End Try

        StopCompiler()

        Me.ClearText()
        If mVerbose Then
            Me.Invoke(d, New Object() {SCI_Output, "Compiler arguments: [" & Me.Arguments & " ]" & _
                                       vbCrLf & vbCrLf})
        End If
        Me.Invoke(d, New Object() {SCI_Output, "_________START_________" & vbCrLf})
        Me.Invoke(d, New Object() {SCI_Error, "_________START_________" & vbCrLf})

        ButtonStopCompiler.Enabled = True
        ButtonSaveCompiler.Enabled = False
        ButtonFindError.Text = "&Go to error ->"
        ButtonFindError.BackColor = Color.Transparent
        ButtonFindError.Enabled = False

        Try
            Dim ret As Boolean = process1.Start()
            If ret Then
                process1.StandardInput.AutoFlush = True
                process1.StandardOutput.BaseStream.BeginRead(wxOutputBuffer, _
                                                             0, wxOutputBuffer.Length, _
                                                             New AsyncCallback(AddressOf ReadCallback), _
                                                             Nothing)
                process1.StandardError.BaseStream.BeginRead(wxErrorBuffer, _
                                                            0, wxErrorBuffer.Length, _
                                                            New AsyncCallback(AddressOf ErrorCallback), _
                                                            Nothing)
            End If
            Return True

        Catch
            Return False
        End Try

    End Function


    Private Sub ReadCallback(ByVal ar As IAsyncResult)
        Try
            Me.Invoke(d, New Object() {SCI_Output, Encoding.ASCII.GetString(wxOutputBuffer, 0, process1.StandardOutput.BaseStream.EndRead(ar))})

            If process1.HasExited Then
                Me.Invoke(d, New Object() {SCI_Output, process1.StandardOutput.ReadToEnd()})
            Else
                process1.StandardOutput.BaseStream.BeginRead(wxOutputBuffer, _
                                                             0, wxOutputBuffer.Length, _
                                                             New AsyncCallback(AddressOf ReadCallback), _
                                                             Nothing)
            End If

        Catch ex As Exception
            ''wxMessageError(ex.Message, "wxCompilerConsole - ReadCallback Error")
        End Try
    End Sub

    Private Sub ErrorCallback(ByVal ar As IAsyncResult)
        Try
            Me.Invoke(d, New Object() {SCI_Error, Encoding.ASCII.GetString(wxErrorBuffer, 0, process1.StandardError.BaseStream.EndRead(ar))})

            If process1.HasExited Then
                Me.Invoke(d, New Object() {SCI_Error, process1.StandardError.ReadToEnd()})
            Else
                process1.StandardError.BaseStream.BeginRead(wxErrorBuffer, _
                                                            0, wxErrorBuffer.Length, _
                                                            New AsyncCallback(AddressOf ErrorCallback), _
                                                            Nothing)
            End If

        Catch ex As Exception
            ''wxMessageError(ex.Message, "wxCompilerConsole - ErrorCallback Error")
        End Try
    End Sub

    Private Sub AppendText(ByVal mOutputWin As SCI_EDIT, ByVal mString As String)
        Try
            mOutputWin.SetReadOnly(False)
            mOutputWin.AppendText(mString)
            mOutputWin.GotoPos(mOutputWin.GetLength - 1)
            mOutputWin.SetReadOnly(True)
        Catch ex As Exception
        End Try
    End Sub


    Private Sub ButtonStopCompiler_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonStopCompiler.Click
        Me.StopCompiler()
    End Sub

    Private Sub process1_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles process1.Exited
        ButtonStopCompiler.Enabled = False
        ButtonSaveCompiler.Enabled = True

        Me.Invoke(d, New Object() {SCI_Output, "__________END__________"})
        Me.Invoke(d, New Object() {SCI_Error, "__________END__________"})


        Dim mError As String = FindError(SCI_Error)
        Dim mWave As String = FindSounds(SCI_Output)

        RaiseEvent CompilerCompleted(mError, mWave)

    End Sub


    Private Function FindError(ByVal mOutputWin As SCI_EDIT) As String

        Dim StringToFind As String = "error"
        Dim mStart As Int32 = 0
        Dim mEnd As Int32 = mOutputWin.GetTextLength
        Dim mFindPos As Int32 = -1

        Try
            mOutputWin.SetTargetStart(mStart)
            mOutputWin.SetTargetEnd(mEnd)
            mOutputWin.SetSearchFlags(SCFIND_WHOLEWORD Or SCFIND_MATCHCASE)

            mFindPos = mOutputWin.SearchInTarget(StringToFind)
            If mFindPos > -1 Then
                Dim mLineNumber As Int32 = mOutputWin.LineFromPosition(mFindPos)
                Dim mLine As String = mOutputWin.GetLine(mLineNumber) ''.Trim

                mFindPos = mLine.IndexOf("line")
                ''Dim c As Char
                Dim tempNumber As String = ""
                If mFindPos > 1 Then
                    Return mOutputWin.GetLine(mLineNumber + 1).TrimEnd

                    ''For StartPos As Int32 = mFindPos + 4 To mLine.Length - 1
                    ''    c = Mid(mLine, StartPos + 1, 1)
                    ''    ' Allow digits, letters, and underscores.
                    ''    If Not ( _
                    ''        (c >= "0" And c <= "9" Or c = " ") _
                    ''    ) Then Exit For
                    ''    tempNumber += c
                    ''Next StartPos
                    ''Dim mLineInt As Int32 = CInt(tempNumber.Trim)
                    ''Return mLineInt

                Else
                    Return ""

                End If

            Else
                Return ""

            End If

        Catch ex As Exception
            Return ""

        End Try

    End Function

    Private Function FindSounds(ByVal mOutputWin As SCI_EDIT) As String

        Dim StringToFind As String = ".wav"
        Dim mStart As Int32 = mOutputWin.GetTextLength ''0
        Dim mEnd As Int32 = 0 ''mOutputWin.GetTextLength
        Dim mFindPos As Int32 = -1

        Try
            mOutputWin.SetTargetStart(mStart)
            mOutputWin.SetTargetEnd(mEnd)
            mOutputWin.SetSearchFlags(0) ''SCFIND_WHOLEWORD) ' Or SCFIND_MATCHCASE)

            mFindPos = mOutputWin.SearchInTarget(StringToFind)
            If mFindPos > -1 Then
                Dim mLine As String = mOutputWin.GetLine(mOutputWin.LineFromPosition(mFindPos)).Trim
                mLine = mLine.ToLower
                If Not mLine.Contains("written") Then
                    If Not mLine.Contains("writing") Then Return ""
                End If


                mFindPos = mLine.IndexOf(".wav")
                Dim c As Char
                Dim tempString As String = ""
                If mFindPos > 1 Then
                    For StartPos As Int32 = mFindPos To 1 Step -1
                        c = Mid(mLine, StartPos, 1)
                        If c = " " Then Exit For
                        tempString = c & tempString
                    Next StartPos

                    'debug.writeline("FINDSOUNDS: " & mLine)
                    Return tempString & ".wav"

                Else
                    Return ""

                End If

            Else
                Return ""

            End If

        Catch ex As Exception
            Return ""

        End Try

    End Function

    Private Sub ConfigureSciEditOW(ByVal SciEditOW As SCI_EDIT)
        'Set CodePage
        SciEditOW.SetCodePage(SC_CP_UTF8)
        For Ciclo As Int32 = 0 To 32
            SciEditOW.StyleSetBack(Ciclo, RGB(255, 255, 245))
        Next

        SciEditOW.LineNumbers = False

        'Set Syntax foreground colors
        SciEditOW.StyleSetFore(0, RGB(0, 0, 0))                  'Default Text
        SciEditOW.StyleSetFore(11, RGB(0, 0, 0))                 'Default Text
        SciEditOW.StyleSetFore(1, RGB(0, 0, 0))                  'Comment Multi /**/
        SciEditOW.StyleSetFore(2, RGB(0, 0, 0))                  'Comment Line //
        'SciEditOW.StyleSetFore(3, RGB(255, 0, 0))
        SciEditOW.StyleSetFore(4, RGB(0, 0, 255))                'Numbers color
        SciEditOW.StyleSetFore(5, RGB(255, 0, 0))                'Error colors
        SciEditOW.StyleSetFore(6, RGB(50, 50, 0))                'Double quoted string
        'SciEditOW.StyleSetFore(7, RGB(255, 0, 0))
        SciEditOW.StyleSetFore(9, RGB(0, 0, 0))                  'Preprocessor and Macro
        SciEditOW.StyleSetFore(10, RGB(0, 0, 0))                 'Operator [=] color
        SciEditOW.StyleSetFore(16, RGB(0, 0, 255))               'CSD Tags color

        'Set Syntax Language
        SciEditOW.SetLexerLanguage("cpp")

        'Set ErrorWordList list 
        Dim ErrorWordList As String = "ERROR Error error ERROR: Error: error: "
        SciEditOW.SetKeyWords(0, ErrorWordList)

        Dim TagWordList As String = "Csound Version Command "
        SciEditOW.SetKeyWords(1, TagWordList)

        'SciEditOW.SetWordChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.$_")

        SciEditOW.UsePopup(False)

        'Set ReadOnly
        SciEditOW.SetReadOnly(True)

    End Sub


    Private Sub SCI_Output_KeyDown(ByVal sender As SCI_EDIT, ByVal mKey As Integer, ByVal mModifiers As Integer) Handles SCI_Output.KeyDown, SCI_Error.KeyDown
        Select Case mKey

            Case Keys.Escape
                ButtonStopCompiler.PerformClick()
                Me.OnKeyDown(New System.Windows.Forms.KeyEventArgs(Keys.Escape))

        End Select
    End Sub


    Private Sub wxCompilerConsole_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        Try
            ControlPaint.DrawBorder3D(e.Graphics, 0, 0, Me.Width, Me.Height)
        Catch ex As Exception
        End Try
    End Sub

    Private Sub ButtonFindError_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonFindError.Click
        RaiseEvent ButtonFindErrorClick()
    End Sub

    Private Sub ButtonSaveCompiler_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSaveCompiler.Click
        'Save CompilerOutput Text
        Try
            Dim saveFileDialog1 As New SaveFileDialog

            saveFileDialog1.Filter = "Text file (*.txt)|*.txt|All files (*.*)|*.*"
            saveFileDialog1.FilterIndex = 1
            saveFileDialog1.RestoreDirectory = True

            'If mWorkingDir Then
            '    saveFileDialog1.InitialDirectory = Preferences.Directory.WorkingDir
            '    mWorkingDir = False
            'End If

            If Not (saveFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK) Or _
                    saveFileDialog1.FileName = vbNullString Then
                Exit Sub
            End If

            ''Dim mString As String = ""
            ''SciEditOW.Save(saveFileDialog1.FileName)
            System.IO.File.WriteAllText(saveFileDialog1.FileName, Me.OutputText)

        Catch ex As Exception
            wxMessageError(ex.Message, "wxCompilerConsole - ButtonSaveCompiler_Click Error")
        End Try
    End Sub



End Class
